/*
** $Id: lobject.h $
** Lua对象类型定义
** See Copyright Notice in lua.h
*/


#ifndef lobject_h
#define lobject_h


#include <stdarg.h>


#include "llimits.h"
#include "lua.h"


/*
** 可收集的非值类型
*/
#define LUA_TUPVAL	LUA_NUMTYPES  /* upvalues */
#define LUA_TPROTO	(LUA_NUMTYPES+1)  /* 函数原型 */
#define LUA_TDEADKEY	(LUA_NUMTYPES+2)  /* table中移除的key */



/*
** 所有可能的类型数量 (包括不是DEADKEY的LUA_TNONE)
*/
#define LUA_TOTALTYPES		(LUA_TPROTO + 2)


/*
** tag: TValue的tt_
** 0-3位: 类型精确类型(LUA_T* 常量)
** bits 4-5: 变体位(variant bits)
** bit 6: 是否值可被gc收集
*/

/* 添加类型的变体位 */
#define makevariant(t,v)	((t) | ((v) << 4))



/*
** 所有lua值的union
*/
typedef union Value {
  struct GCObject *gc;    /* 可收集对象(table，string，完整userdata类型等，所有类型查看union GCUnion) */
  void *p;         /* light userdata */
  lua_CFunction f; /* light C functions */
  lua_Integer i;   /* integer numbers */
  lua_Number n;    /* float numbers */
  /* 无用，但可避免未初始化值的警告 */
  lu_byte ub;
} Value;


/*
** 目标值. 这是Lua中的值的基础代理: 一个准确的值加上其类型
*/
#define TValuefields	Value value_; lu_byte tt_

typedef struct TValue {
  TValuefields;
} TValue;


#define val_(o)		((o)->value_)
#define valraw(o)	(val_(o))


/* 原生tag类型，就是TValue的 tt_ 值 */
#define rawtt(o)	((o)->tt_)

/* 没有变体位的类型 (bits 0-3) */
#define novariant(t)	((t) & 0x0F)

/* 包含变体位的类型(bits 0-3 for tags + variant bits 4-5) */
#define withvariant(t)	((t) & 0x3F)
#define ttypetag(o)	withvariant(rawtt(o))

/* 根据值获取对应tag类型 */
#define ttype(o)	(novariant(rawtt(o)))


/* 检查类型 */
#define checktag(o,t)		(rawtt(o) == (t))
#define checktype(o,t)		(ttype(o) == (t))


/* 内部检测宏 */

/* 可收集对象拥有相同的tag作为原始值 */
#define righttt(obj)		(ttypetag(obj) == gcvalue(obj)->tt)

/*
** 检测活性，程序操作的任何值要么是不可收集的，要么可收集的对象有正确的标记，并且它不是死的。选项'L == NULL'允许在L不可用的地方使用使用此选项的其他宏。
*/
#define checkliveness(L,obj) \
	((void)L, lua_longassert(!iscollectable(obj) || \
		(righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj))))))


/* 设置值的宏 */

/* 设置类型 */
#define settt_(o,t)	((o)->tt_=(t))


/* 将obj2的值复制到obj1 */
#define setobj(L,obj1,obj2) \
	{ TValue *io1=(obj1); const TValue *io2=(obj2); \
          io1->value_ = io2->value_; settt_(io1, io2->tt_); \
	  checkliveness(L,io1); lua_assert(!isnonstrictnil(io1)); }

/*
**  根据源和目标区分的不同类型的分配
** (它们现在基本上是相等的，但将来可能会有所不同)
*/

/* stack -> stack */
#define setobjs2s(L,o1,o2)	setobj(L,s2v(o1),s2v(o2))
/* other stack -> stack */
#define setobj2s(L,o1,o2)	setobj(L,s2v(o1),o2)
/* table -> same table */
#define setobjt2t	setobj
/* to new object */
#define setobj2n	setobj
/* to table */
#define setobj2t	setobj


/*
** Lua栈中的元素，tbclist字段列出了该栈中所有激活的待关闭的条目列表
** 两个tbc变量间不能使用无符号short类型来表示距离时使用虚拟元素，他们用delta==0来表示，它们的真实delta值总是符合该域的最大值。
*/
typedef union StackValue {
  TValue val;
  struct {
    TValuefields;
    unsigned short delta;
  } tbclist;
} StackValue;


/* index -> stack元素 */
typedef StackValue *StkId;


/*
** 在给一个栈重新分配内存时，将所有指向堆栈的指针更改为适当的偏移量
*/
typedef union {
  StkId p;  /* 实际指针 */
  ptrdiff_t offset;  /* 当栈被重新分配时使用 */
} StkIdRel;


/* 获取StackValue的val */
#define s2v(o)	(&(o)->val)



/*
** {==================================================================
** Nil
** ===================================================================
*/

/* 标准nil值 */
#define LUA_VNIL	makevariant(LUA_TNIL, 0)

/* 空节点 (区别于包含nil的slot) */
#define LUA_VEMPTY	makevariant(LUA_TNIL, 1)

/* 表中未找到key的返回值(缺席值) */
#define LUA_VABSTKEY	makevariant(LUA_TNIL, 2)


/* 测试值是否是任何一种nil */
#define ttisnil(v)		checktype((v), LUA_TNIL)


/* 测试值是否是标准nil */
#define ttisstrictnil(o)	checktag((o), LUA_VNIL)

/* nil没有设置值，只设置了类型为nil */
#define setnilvalue(obj) settt_(obj, LUA_VNIL)


/* 是否是一个缺席值 */
#define isabstkey(v)		checktag((v), LUA_VABSTKEY)


/*
** 是否是nil但不是标准nil (只在断言(assert)中使用)
*/
#define isnonstrictnil(v)	(ttisnil(v) && !ttisstrictnil(v))


/*
** 默认的，任何类型的nil值都被视为空(在任何定义中，与缺席键关联的值也必须被接受为空)
*/
#define isempty(v)		ttisnil(v)


/* 与缺席值对应的TValue */
#define ABSTKEYCONSTANT		{NULL}, LUA_VABSTKEY


/* 设置一个条目为空 */
#define setempty(v)		settt_(v, LUA_VEMPTY)



/* }================================================================== */


/*
** {==================================================================
** Booleans
** ===================================================================
*/


#define LUA_VFALSE	makevariant(LUA_TBOOLEAN, 0)
#define LUA_VTRUE	makevariant(LUA_TBOOLEAN, 1)

#define ttisboolean(o)		checktype((o), LUA_TBOOLEAN)
#define ttisfalse(o)		checktag((o), LUA_VFALSE)
#define ttistrue(o)		checktag((o), LUA_VTRUE)


#define l_isfalse(o)	(ttisfalse(o) || ttisnil(o))


#define setbfvalue(obj)		settt_(obj, LUA_VFALSE)
#define setbtvalue(obj)		settt_(obj, LUA_VTRUE)

/* }================================================================== */


/*
** {==================================================================
** Threads
** ===================================================================
*/

// 变量的线程类型
#define LUA_VTHREAD		makevariant(LUA_TTHREAD, 0)

#define ttisthread(o)		checktag((o), ctb(LUA_VTHREAD))

#define thvalue(o)	check_exp(ttisthread(o), gco2th(val_(o).gc))

#define setthvalue(L,obj,x) \
  { TValue *io = (obj); lua_State *x_ = (x); \
    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VTHREAD)); \
    checkliveness(L,io); }

#define setthvalue2s(L,o,t)	setthvalue(L,s2v(o),t)

/* }================================================================== */


/*
** {==================================================================
** 可收集对象GCObject
** ===================================================================
*/

/*
** 所有gc对象公共的通用header (以宏形式的形式包含在其他对象中)
** next: 下一个GCObject
** tt: 对象类型
** marked: 标记
*/
#define CommonHeader	struct GCObject *next; lu_byte tt; lu_byte marked


/* gc对象类型 */
typedef struct GCObject {
  CommonHeader;
} GCObject;


/* 标记为可回收类型 */
#define BIT_ISCOLLECTABLE	(1 << 6)

#define iscollectable(o)	(rawtt(o) & BIT_ISCOLLECTABLE)

/* 标记为可收集 */
#define ctb(t)			((t) | BIT_ISCOLLECTABLE)

#define gcvalue(o)	check_exp(iscollectable(o), val_(o).gc)

#define gcvalueraw(v)	((v).gc)

#define setgcovalue(L,obj,x) \
  { TValue *io = (obj); GCObject *i_g=(x); \
    val_(io).gc = i_g; settt_(io, ctb(i_g->tt)); }

/* }================================================================== */


/*
** {==================================================================
** Numbers
** ===================================================================
*/

/* 数字变体 */
#define LUA_VNUMINT	makevariant(LUA_TNUMBER, 0)  /* 整型数字 */
#define LUA_VNUMFLT	makevariant(LUA_TNUMBER, 1)  /* 浮点型数字 */

#define ttisnumber(o)		checktype((o), LUA_TNUMBER)
#define ttisfloat(o)		checktag((o), LUA_VNUMFLT)
#define ttisinteger(o)		checktag((o), LUA_VNUMINT)

#define nvalue(o)	check_exp(ttisnumber(o), \
	(ttisinteger(o) ? cast_num(ivalue(o)) : fltvalue(o)))
#define fltvalue(o)	check_exp(ttisfloat(o), val_(o).n)
#define ivalue(o)	check_exp(ttisinteger(o), val_(o).i)

#define fltvalueraw(v)	((v).n)
#define ivalueraw(v)	((v).i)

#define setfltvalue(obj,x) \
  { TValue *io=(obj); val_(io).n=(x); settt_(io, LUA_VNUMFLT); }

#define chgfltvalue(obj,x) \
  { TValue *io=(obj); lua_assert(ttisfloat(io)); val_(io).n=(x); }

#define setivalue(obj,x) \
  { TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_VNUMINT); }

#define chgivalue(obj,x) \
  { TValue *io=(obj); lua_assert(ttisinteger(io)); val_(io).i=(x); }

/* }================================================================== */


/*
** {==================================================================
** Strings
** ===================================================================
*/

#define LUA_VSHRSTR	makevariant(LUA_TSTRING, 0)  /* 短字符串 */
#define LUA_VLNGSTR	makevariant(LUA_TSTRING, 1)  /* 长字符串 */

#define ttisstring(o)		checktype((o), LUA_TSTRING)
#define ttisshrstring(o)	checktag((o), ctb(LUA_VSHRSTR))
#define ttislngstring(o)	checktag((o), ctb(LUA_VLNGSTR))

#define tsvalueraw(v)	(gco2ts((v).gc))

#define tsvalue(o)	check_exp(ttisstring(o), gco2ts(val_(o).gc))

#define setsvalue(L,obj,x) \
  { TValue *io = (obj); TString *x_ = (x); \
    val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \
    checkliveness(L,io); }

/* 设置字符串到栈中 */
#define setsvalue2s(L,o,s)	setsvalue(L,s2v(o),s)

/* 设置字符串到新对象 */
#define setsvalue2n	setsvalue


/*
** 字符串值的头
*/
typedef struct TString {
  CommonHeader;
  lu_byte extra;  /* 短字符串是否为保留字，长字符串是否有hash值 */
  lu_byte shrlen;  /* 短字符串的长度 */
  unsigned int hash;
  union {
    size_t lnglen;  /* 长字符串的长度 */
    struct TString *hnext;  /* 指向下一个短字符串 */
  } u;
  char contents[1];
} TString;


/*
** 从一个'TString'中获取精确的字符串(byte数组)
*/
#define getstr(ts)  ((ts)->contents)


/* 从一个Lua值中获取字符串(byte数组) */
#define svalue(o)       getstr(tsvalue(o))

/* 从一个‘TString*’中获取字符串长度 */
#define tsslen(s)	((s)->tt == LUA_VSHRSTR ? (s)->shrlen : (s)->u.lnglen)

/* 从一个‘TValue*’中获取字符串长度 ' */
#define vslen(o)	tsslen(tsvalue(o))

/* }================================================================== */


/*
** {==================================================================
** Userdata
** ===================================================================
*/


/*
** lightuserdata应该是userdata的一个变体，但是由于兼容原因，他们仍然是不同的类型
*/
#define LUA_VLIGHTUSERDATA	makevariant(LUA_TLIGHTUSERDATA, 0)

#define LUA_VUSERDATA		makevariant(LUA_TUSERDATA, 0)

#define ttislightuserdata(o)	checktag((o), LUA_VLIGHTUSERDATA)
#define ttisfulluserdata(o)	checktag((o), ctb(LUA_VUSERDATA))

#define pvalue(o)	check_exp(ttislightuserdata(o), val_(o).p)
#define uvalue(o)	check_exp(ttisfulluserdata(o), gco2u(val_(o).gc))

#define pvalueraw(v)	((v).p)

#define setpvalue(obj,x) \
  { TValue *io=(obj); val_(io).p=(x); settt_(io, LUA_VLIGHTUSERDATA); }

#define setuvalue(L,obj,x) \
  { TValue *io = (obj); Udata *x_ = (x); \
    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VUSERDATA)); \
    checkliveness(L,io); }


/* 确保此类型之后的地址始终完全对齐 */
typedef union UValue {
  TValue uv;
  LUAI_MAXALIGN;  /* 确保udata字节的最大对齐*/
} UValue;


/*
** 带有user value的userdata的头，内存区域位于该结构的末端
*/
typedef struct Udata {
  CommonHeader;
  unsigned short nuvalue;  /* user value的数量 */
  size_t len;  /* 字节数 */
  struct Table *metatable;
  GCObject *gclist;
  UValue uv[1];  /* user values */
} Udata;


/*
** 没有user value的userdata的头，这些数据在整个GC中都不会变gray，因此不需要‘gclist'字段。
** 为了简化，代码总是对两种类型的用户数据使用'Udata'，确保它永远不会访问没有用户值的用户数据上的'gclist'。此结构仅用于计算此表示的正确大小。('bindata'字段在其末尾确保正确对齐的二进制数据在这个头。)
*/
typedef struct Udata0 {
  CommonHeader;
  unsigned short nuvalue;  /* user values的数量 */
  size_t len;  /* 字节数 */
  struct Table *metatable;
  union {LUAI_MAXALIGN;} bindata;
} Udata0;


/* 计算一个userdata的内存偏移量，nuv: user value的数量(第几个) */
#define udatamemoffset(nuv) \
	((nuv) == 0 ? offsetof(Udata0, bindata)  \
                    : offsetof(Udata, uv) + (sizeof(UValue) * (nuv)))

/* 获取'Udata'内部内存块的地址 */
#define getudatamem(u)	(cast_charp(u) + udatamemoffset((u)->nuvalue))

/* 计算userdata的大小 */
#define sizeudata(nuv,nb)	(udatamemoffset(nuv) + (nb))

/* }================================================================== */


/*
** {==================================================================
** Prototypes
** ===================================================================
*/

#define LUA_VPROTO	makevariant(LUA_TPROTO, 0)


/*
** 函数的upvalue
*/
typedef struct Upvaldesc {
  TString *name;  /* upvalue名称 (用于调试信息) */
  lu_byte instack;  /* 是否在栈中(寄存器) */
  lu_byte idx;  /* upvalue的索引 (栈中/函数列表外) */
  lu_byte kind;  /* 对应变量的类型 */
} Upvaldesc;


/*
** 方法原型的local变量 (used 用于调试信息)
*/
typedef struct LocVar {
  TString *varname;
  int startpc;  /* 变量激活点 */
  int endpc;    /* 变量死亡点 */
} LocVar;


/*
** 行信息
** 将给定指令的绝对行源关联起来('pc').
** 数组'lineinfo'给出了每条指令与前一条指令的行数差异。当差异不能用一个字节表示时，Lua为该指令保存绝对行。
** (Lua还定期保存绝对行，以加快行号的计算:我们可以在绝对行数组中使用二进制搜索，但我们必须线性遍历'lineinfo'数组来计算一行。)
*/
typedef struct AbsLineInfo {
  int pc;
  int line;
} AbsLineInfo;

/*
** 函数原型
*/
typedef struct Proto {
  CommonHeader;
  lu_byte numparams;  /* 固定参数数量 */
  lu_byte is_vararg;  /* 是否接收可变参数 */
  lu_byte maxstacksize;  /* 所需最大栈大小 */
  int sizeupvalues;  /* 'upvalues'大小 */
  int sizek;  /* 'k'大小 */
  int sizecode; /* code大小 */
  int sizelineinfo; /* lineinfo大小 */
  int sizep;  /* 'p'尺寸(可容纳大小) */
  int sizelocvars;
  int sizeabslineinfo;  /* 'abslineinfo'大小 */
  int linedefined;  /* 函数定义开始行号(debug)  */
  int lastlinedefined;  /* 函数定义结束行号(debug)  */
  TValue *k;  /* 用于函数的常量(number, bool, string, ...) */
  Instruction *code;  /* 当前函数的OpCode指令数组 */
  struct Proto **p;  /* 这个方法中定义的方法 */
  Upvaldesc *upvalues;  /* upvalue信息 */
  ls_byte *lineinfo;  /* information about source lines (debug) */
  AbsLineInfo *abslineinfo;  /* idem */
  LocVar *locvars;  /* 局部变量 (debug) */
  TString  *source;  /* 函数源代码(debug) */
  GCObject *gclist;
} Proto;

/* }================================================================== */


/*
** {==================================================================
** Functions
** ===================================================================
*/

#define LUA_VUPVAL	makevariant(LUA_TUPVAL, 0)


#define LUA_VLCL	makevariant(LUA_TFUNCTION, 0)  /* Lua 闭包 */
#define LUA_VLCF	makevariant(LUA_TFUNCTION, 1)  /* 轻量 C 函数 */
#define LUA_VCCL	makevariant(LUA_TFUNCTION, 2)  /* C 闭包 */

#define ttisfunction(o)		checktype(o, LUA_TFUNCTION)
#define ttisLclosure(o)		checktag((o), ctb(LUA_VLCL))
#define ttislcf(o)		checktag((o), LUA_VLCF)
#define ttisCclosure(o)		checktag((o), ctb(LUA_VCCL))
#define ttisclosure(o)         (ttisLclosure(o) || ttisCclosure(o))


#define isLfunction(o)	ttisLclosure(o)

#define clvalue(o)	check_exp(ttisclosure(o), gco2cl(val_(o).gc))
#define clLvalue(o)	check_exp(ttisLclosure(o), gco2lcl(val_(o).gc))
#define fvalue(o)	check_exp(ttislcf(o), val_(o).f)
#define clCvalue(o)	check_exp(ttisCclosure(o), gco2ccl(val_(o).gc))

#define fvalueraw(v)	((v).f)

#define setclLvalue(L,obj,x) \
  { TValue *io = (obj); LClosure *x_ = (x); \
    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VLCL)); \
    checkliveness(L,io); }

#define setclLvalue2s(L,o,cl)	setclLvalue(L,s2v(o),cl)

#define setfvalue(obj,x) \
  { TValue *io=(obj); val_(io).f=(x); settt_(io, LUA_VLCF); }

#define setclCvalue(L,obj,x) \
  { TValue *io = (obj); CClosure *x_ = (x); \
    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VCCL)); \
    checkliveness(L,io); }


/*
** Lua闭包的upvalue
*/
typedef struct UpVal {
  CommonHeader;
  union {
    TValue *p;  /* 指向栈或自身的指针 */
    ptrdiff_t offset;  /* 栈重新分配期间使用 */
  } v;
  union {
    struct {  /* 打开时 */
      struct UpVal *next;  /* 链表 */
      struct UpVal **previous;
    } open;
    TValue value;  /* 值(关闭时) */
  } u;
} UpVal;



#define ClosureHeader \
	CommonHeader; lu_byte nupvalues; GCObject *gclist

typedef struct CClosure {
  ClosureHeader;
  lua_CFunction f;
  TValue upvalue[1];  /* upvalue列表 */
} CClosure;


typedef struct LClosure {
  ClosureHeader;
  struct Proto *p;  /* 函数原型 */
  UpVal *upvals[1];  /* upvalue列表 */
} LClosure;


typedef union Closure {
  CClosure c;
  LClosure l;
} Closure;


#define getproto(o)	(clLvalue(o)->p)

/* }================================================================== */


/*
** {==================================================================
** Tables
** ===================================================================
*/

#define LUA_VTABLE	makevariant(LUA_TTABLE, 0)

#define ttistable(o)		checktag((o), ctb(LUA_VTABLE))

#define hvalue(o)	check_exp(ttistable(o), gco2t(val_(o).gc))

#define sethvalue(L,obj,x) \
  { TValue *io = (obj); Table *x_ = (x); \
    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VTABLE)); \
    checkliveness(L,io); }

#define sethvalue2s(L,o,h)	sethvalue(L,s2v(o),h)


/*
** hash表的节点：一个由两个TValue(键值对)组成的包，加上一个'next'字段来链接冲突的条目。
** key字段的分布('key_tt' and 'key_val') not forming a proper 'TValue' allows for a smaller size for 'Node' both in 4-byte and 8-byte alignments.
*/
typedef union Node {
  struct NodeKey {
    TValuefields;  /* 值 */
    lu_byte key_tt;  /* key的类型 */
    int next;  /* 用于链表(hash碰撞时)，取值为链表结构和节点的相对位置 */
    Value key_val;  /* key的值 */
  } u;
  TValue i_val;  /* 直接访问节点的值作为适当的'TValue' */
} Node;


/* 复制值到key */
#define setnodekey(L,node,obj) \
	{ Node *n_=(node); const TValue *io_=(obj); \
	  n_->u.key_val = io_->value_; n_->u.key_tt = io_->tt_; \
	  checkliveness(L,io_); }


/* 从key中复制值 */
#define getnodekey(L,obj,node) \
	{ TValue *io_=(obj); const Node *n_=(node); \
	  io_->value_ = n_->u.key_val; io_->tt_ = n_->u.key_tt; \
	  checkliveness(L,io_); }


#define BITRAS		(1 << 7)
/* 如果'isrealasize(t)'是true，那么’alimit'是数组的真实长度， */
#define isrealasize(t)		(!((t)->flags & BITRAS))
#define setrealasize(t)		((t)->flags &= cast_byte(~BITRAS))
#define setnorealasize(t)	((t)->flags |= BITRAS)

/*
** alimit: 如果'isrealasize(t)'是true，那么’alimit'是数组的真实长度，否则，设数组长度为2^n,2^(n-1) < 'array'的实际大小 < 2^n(如果'alimit'为零，则为零);
** ’alimit'用于做#t的提示
*/
typedef struct Table {
  CommonHeader;
  lu_byte flags;  /* 1<<p 表示 tagmethod(p) 不存在 */
  lu_byte lsizenode;  /* Node数组(hash部分)长度的log2 */
  unsigned int alimit;  /* 'array' 数组的 "limit" */
  TValue *array;  /* 数组部分 */
  Node *node; /* hash部分 */
  Node *lastfree;  /* 最后一个空闲节点，所有的空位都在这个位置之前 */
  struct Table *metatable;
  GCObject *gclist;
} Table;


/*
** 用于操作节点中插入的key的宏
*/
#define keytt(node)		((node)->u.key_tt)
#define keyval(node)		((node)->u.key_val)

#define keyisnil(node)		(keytt(node) == LUA_TNIL)
#define keyisinteger(node)	(keytt(node) == LUA_VNUMINT)
#define keyival(node)		(keyval(node).i)
#define keyisshrstr(node)	(keytt(node) == ctb(LUA_VSHRSTR))
#define keystrval(node)		(gco2ts(keyval(node).gc))

#define setnilkey(node)		(keytt(node) = LUA_TNIL)

#define keyiscollectable(n)	(keytt(n) & BIT_ISCOLLECTABLE)

#define gckey(n)	(keyval(n).gc)
#define gckeyN(n)	(keyiscollectable(n) ? gckey(n) : NULL)


/*
** 表中的死键具有DEADKEY标签，但保持其原始gcvalue
** 这将他们与普通key区分开，但允许他们被以特殊方式搜索时被找到
** ('next'需要查找遍历期间从表中删除的key)
*/
#define setdeadkey(node)	(keytt(node) = LUA_TDEADKEY)
#define keyisdead(node)		(keytt(node) == LUA_TDEADKEY)

/* }================================================================== */



/*
** hash的取模操作(size总是2的次方)
*/
#define lmod(s,size) \
	(check_exp((size&(size-1))==0, (cast_int((s) & ((size)-1)))))


#define twoto(x)	(1<<(x))
#define sizenode(t)	(twoto((t)->lsizenode))


/* 'luaO_utf8esc'函数的缓冲区大小 */
#define UTF8BUFFSZ	8

LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x);
LUAI_FUNC int luaO_ceillog2 (unsigned int x);
LUAI_FUNC int luaO_rawarith (lua_State *L, int op, const TValue *p1,
                             const TValue *p2, TValue *res);
LUAI_FUNC void luaO_arith (lua_State *L, int op, const TValue *p1,
                           const TValue *p2, StkId res);
LUAI_FUNC size_t luaO_str2num (const char *s, TValue *o);
LUAI_FUNC int luaO_hexavalue (int c);
LUAI_FUNC void luaO_tostring (lua_State *L, TValue *obj);
LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt,
                                                       va_list argp);
LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...);
LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t srclen);


#endif

